package org.fujay.langchain4jserver.domain.shared.service;

import org.fujay.langchain4jserver.domain.knowledge.entity.File;
import org.fujay.langchain4jserver.domain.knowledge.vo.StorageStrategy;
import org.fujay.langchain4jserver.domain.shared.exception.FileStorageException;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Optional;

/**
 * 文件存储提供者领域服务接口 (由基础设施层实现，适配具体的存储方案，如本地磁盘, OSS, S3 等)
 */
public interface StorageProvider {

    /**
     * 将输入流存储到指定的路径。 实现类负责处理流的关闭。
     *
     * @param inputStream 要存储的输入流
     * @param filePath    建议的存储路径 (实现类可能会修改以确保唯一性)
     * @param strategy    存储策略
     * @return 实际存储的文件路径
     * @throws FileStorageException 存储失败时抛出
     */
    String store(InputStream inputStream, String filePath, StorageStrategy strategy)
            throws FileStorageException;

    /**
     * 获取文件的输入流
     *
     * @param file 文件实体 (包含 filePath, storageStrategy 等信息)
     * @return 文件的 InputStream
     * @throws FileStorageException 获取文件流失败
     */
    InputStream getFileStream(File file) throws FileStorageException, IOException;

    /**
     * 获取用于写入文件的输出流 (例如，用于分块上传的合并) 调用者负责在使用后关闭流。
     *
     * @param filePath 指定的存储路径
     * @param strategy 存储策略 (用于确定写入位置)
     * @return 可写入的 OutputStream
     * @throws FileStorageException 获取输出流失败
     */
    @Deprecated
    // 推荐使用 store 方法
    OutputStream getOutputStream(String filePath, StorageStrategy strategy)
            throws FileStorageException;

    /**
     * 删除文件
     *
     * @param file 文件实体
     * @throws FileStorageException 删除失败
     */
    void deleteFile(File file) throws FileStorageException;

    /**
     * 获取文件的可访问 URL (如果存储策略支持)
     *
     * @param file              文件实体
     * @param expirationSeconds URL 有效期（秒），null 表示永久或默认策略
     * @return 文件 URL Optional，如果不支持或失败则为空
     */
    Optional<String> getFileUrl(File file, Integer expirationSeconds);

    /**
     * 检查文件是否存在
     *
     * @param file 文件实体
     * @return true 如果文件存在, false 否则
     */
    boolean fileExists(File file);

    // 可能还需要其他方法，例如获取文件大小、移动文件等
}
